package com.chenyun.system.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.chenyun.common.constants.AuthConstant;
import com.chenyun.common.context.SpringContext;
import com.chenyun.common.enums.LoginDeviceTypeEnum;
import com.chenyun.common.enums.LoginUserTypeEnum;
import com.chenyun.common.exceptions.BusinessException;
import com.chenyun.common.vo.AjaxResult;
import com.chenyun.common.vo.LoginVO;
import com.chenyun.common.vo.SessionUser;
import com.chenyun.satoken.starter.stp.StpShopUtil;
import com.chenyun.satoken.starter.util.SaUtil;
import com.chenyun.system.event.LoginEvent;
import com.chenyun.system.model.SysRole;
import com.chenyun.system.model.SysUser;
import com.chenyun.system.service.ISysMenuService;
import com.chenyun.system.service.ISysRoleService;
import com.chenyun.system.service.ISysUserService;
import com.chenyun.tenant.TenantContext;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: lonni
 * @CreateTime: 2023-09-11  21:16
 * @Description:
 */
@RestController
@RequestMapping("auth")
@Slf4j
@Api(tags = "平台端登录-admin")
public class LoginController {


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysMenuService menuService;


    @Autowired
    private ISysRoleService roleService;

    /**
     * 统一的 刷新token
     *
     * @return
     */
    @GetMapping("token/refresh")
    @ApiOperation("刷新token")
    public AjaxResult refreshToken(@Valid @NotBlank(message = "刷新token不能为空!") String refreshToken) {
        if (!refreshToken.contains("$")){
            throw new BusinessException("刷新token失败!token不合法;");
        }
        String[] split = refreshToken.split("\\$");
        String token = split[1];
        JWT jwt = JWTUtil.parseToken(token);
        JSONObject payloads = jwt.getPayloads();
        String device = payloads.getStr("device");
        String userId = payloads.getStr("userId");
        String userType = payloads.getStr("userType");
        String loginType = payloads.getStr("loginType");
        String clientId = payloads.getStr("clientId");
        String userName = payloads.getStr("userName");
        if (StrUtil.hasEmpty(device,userId,userType,loginType,userName)){
            throw new BusinessException("刷新token失败!token不合法;");
        }

        Map<String, Object> tokenInfo = new HashMap<>();
        if (userType.equals(LoginUserTypeEnum.PLAT_FORM_ADMIN.getType())) {
            //平台端
            SysUser qUser = new SysUser();
            qUser.setUserName(userName);
            qUser.setUserType("0");
            qUser.setPassword("");
            LoginVO param = new LoginVO();
            param.setUserType(LoginUserTypeEnum.valueOf(userType));
            param.setUsername(userName);
            param.setDeviceType(LoginDeviceTypeEnum.valueOf(device));
            tokenInfo = getTokenInfo(param);
        } else if (userType.equals(LoginUserTypeEnum.BUS_ADMIN.getType())) {
            //商家端
        } else if (userType.equals(LoginUserTypeEnum.MEMBER.getType())) {
            //会员端
        } else {
            throw new BusinessException("无效的端类型");
        }

        return AjaxResult.SUCCESS(tokenInfo);

    }


    /**
     * 平台端登录 验证码登录
     *
     * @param param
     * @return
     */
    @PostMapping("token/code")
    @ApiOperation("平台端-验证码登录")
    public AjaxResult login(@RequestBody LoginVO param) {
//        if (StringUtils.isNotBlank(param.getCode())) {
//            String o = (String) redisTemplate.opsForValue().get(AuthConstant.AUTH_CATCHA_CACHE_KEY + param.getUuid());
//            if (Objects.isNull(o)) {
//                return AjaxResult.FAIL("验证码无效!");
//            }
//            if (!param.getCode().equalsIgnoreCase(o)) {
//                return AjaxResult.FAIL("验证码不正确");
//            }
//        }
        Map<String, Object> tokenInfo = getTokenInfo(param);
        return AjaxResult.SUCCESS(tokenInfo);
    }


    @PostMapping("token/code1")
    @ApiOperation("平台端-测试模拟商户登录")
    public AjaxResult login1(@RequestBody LoginVO param) {
//        if (StringUtils.isNotBlank(param.getCode())) {
//            String o = (String) redisTemplate.opsForValue().get(AuthConstant.AUTH_CATCHA_CACHE_KEY + param.getUuid());
//            if (Objects.isNull(o)) {
//                return AjaxResult.FAIL("验证码无效!");
//            }
//            if (!param.getCode().equalsIgnoreCase(o)) {
//                return AjaxResult.FAIL("验证码不正确");
//            }
//        }
        SysUser qUser = new SysUser();
        qUser.setUserName(param.getUsername());
        qUser.setUserType("0");

        List<SysUser> sysUsers = userService.selectUserList(qUser);
        if (CollectionUtil.isEmpty(sysUsers)) {
            throw new BusinessException("用户不存在");
        }
        qUser = sysUsers.get(0);
        Set<String> menuPer = menuService.selectMenuPermsByUserId(Long.valueOf(qUser.getUserId()));
        SessionUser sessionUser = SessionUser.builder()
                .userId(qUser.getUserId())
                .deptId(Objects.toString(qUser.getDeptId()))
                .userName(qUser.getUserName())
                .nickName(qUser.getNickName())
                .deviceType(param.getDeviceType())
                .userType(LoginUserTypeEnum.BUS_ADMIN)
                .openId(qUser.getOpenId())
                .unionId(qUser.getUnionId())
                .phone(qUser.getPhonenumber())
                .password(qUser.getPassword())
                .shopId("")
                .shopName("")
                .build();
        sessionUser.setRolePermission(qUser.getRoles().stream().map(SysRole::getRoleKey).collect(Collectors.toSet()));
        //赋值权限
        sessionUser.setMenuPermission(menuPer);
        SaUtil.loginByDevice(sessionUser);
        SaTokenInfo tokenInfo = StpShopUtil.getTokenInfo();
        return AjaxResult.SUCCESS(tokenInfo);
    }


    /**
     * 平台端登录 手机号登录
     *
     * @param param
     * @return
     */
    @PostMapping("token/phone")
    @ApiOperation("平台端-手机号登录")
    public AjaxResult loginByPhone(@RequestBody LoginVO param) {
        if (org.apache.commons.lang3.StringUtils.isAnyBlank(param.getCode(), param.getPhone())) {
            return AjaxResult.FAIL("手机号或验证码不能为空!");
        }
        String o = (String) redisTemplate.opsForValue().get(AuthConstant.AUTH_SMS_LOGIN_CACHE_KEY + param.getPhone());
        if (Objects.isNull(o)) {
            return AjaxResult.FAIL("未检测到短信验证码,请重新发送!");
        }
        if (!param.getCode().equalsIgnoreCase(o)) {
            return AjaxResult.FAIL("短信验证码不正确");
        }
        Map<String, Object> tokenInfo = getTokenInfo(param);
        return AjaxResult.SUCCESS(tokenInfo);
    }


    @GetMapping("getUserInfo")
    @ApiOperation("获取用户信息")
    public AjaxResult getUserInfo() {
        SessionUser user = SaUtil.sessionUser();
        //查询用户信息i
        SysUser sysUser = userService.selectUserById(Long.valueOf(user.getUserId()));
        HashMap<String, Object> hashMap = new HashMap<String, Object>() {{
            put("userInfo", sysUser);
            put("menuPermission", user.getMenuPermission());
        }};
        return AjaxResult.SUCCESS(hashMap);
    }

    @GetMapping("logout")
    @ApiOperation("退出登陆")
    public AjaxResult logout() {
        log.info("退出登录");
        SaUtil.logout();
        return AjaxResult.SUCCESS();
    }


    private Map<String, Object> getTokenInfo(LoginVO param) {

        TenantContext.me.setIgnoreTenant(true);
        SysUser qUser = new SysUser();
        if (StrUtil.isNotBlank(param.getUsername())) {
            qUser.setUserName(param.getUsername());
        }
        if (StrUtil.isNotBlank(param.getPhone())) {
            qUser.setPhonenumber(param.getPhone());
        }
        qUser.setUserType("0");
        List<SysUser> sysUsers = userService.selectUserList(qUser);
        SessionUser sessionUser1 = new SessionUser();
        sessionUser1.setUserName(qUser.getUserName());
        if (CollectionUtil.isEmpty(sysUsers)) {
            SpringContext.publishEvent(new LoginEvent(this, sessionUser1, false, "用户不存在"));
            throw new BusinessException("用户不存在");
        }
        try {
            qUser = sysUsers.get(0);
            qUser.setDept(null);
            //校验密码
            if (StrUtil.isNotBlank(param.getPassword())) {
                String pwd = DigestUtil.sha1Hex(param.getPassword());
                if (!pwd.equals(qUser.getPassword())) {
                    throw new BusinessException("密码错误!");
                }
            }
            //设置tenantid
            TenantContext.me.setIgnoreTenant(false);
            TenantContext.me.setTenantId(qUser.getTenantId().toString());
            Set<String> menuPer = menuService.selectMenuPermsByUserId(Long.valueOf(qUser.getUserId()));
            Set<String> roles = roleService.selectRolePermissionByUserId(Long.valueOf(qUser.getUserId()));

            SessionUser sessionUser = SessionUser.builder()
                    .userId(qUser.getUserId())
                    .deptId(Objects.toString(qUser.getDeptId()))
                    .userName(qUser.getUserName())
                    .nickName(qUser.getNickName())
                    .deviceType(param.getDeviceType())
                    .userType(param.getUserType())
                    .openId(qUser.getOpenId())
                    .unionId(qUser.getUnionId())
                    .phone(qUser.getPhonenumber())
                    .password(qUser.getPassword())
                    .clientId(qUser.getTenantId().toString())
                    .shopId("")
                    .shopName("")
                    .build();
            sessionUser.setRolePermission(roles);
            //赋值权限
            sessionUser.setMenuPermission(menuPer);
            SaUtil.loginByDevice(sessionUser);
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
            //计算时间戳
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime localDateTime = now.plusSeconds(tokenInfo.getTokenTimeout());
            //在此基础上减去5秒
            localDateTime = localDateTime.minusSeconds(5);
            long createTime = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
            Map<String, Object> map = BeanUtil.beanToMap(tokenInfo);
            map.put("user", qUser);
            map.put("timespan", createTime);
            //发布登录成功事件
            SpringContext.publishEvent(new LoginEvent(this, sessionUser, true, "登录成功"));
            return map;
        } catch (Exception exception) {
            SpringContext.publishEvent(new LoginEvent(this, sessionUser1, false, exception.getLocalizedMessage()));
            throw exception;
        }


    }


}
